package com.example.spring.redis.common.util;

import lombok.Getter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * Redis 访问助手
 * </p>
 *
 * @author Ashe
 * @version V1.0.0
 * @date 2019/12/26 0026$ 16:01$
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify By: {修改人} 2019/12/26 0026$
 * @modify reason: {方法名}:{原因}
 * ...
 * @since V1.0.0
 */
@Component
@Getter
public class RedisAssistant {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 有效期管理封装
     */
    private ExpireSupport expireSupport = new ExpireSupport();
    /**
     * 公共操作封装
     */
    private CommonOperationSupport commonOperationSupport = new CommonOperationSupport();
    /**
     * Hash 结构数据操作封装
     */
    private HashSupport hashSupport = new HashSupport();

    /**
     * 内部实现分为
     * - 时间过期管理
     * - 不同数据类型管理 增删改
     * - 分布式锁支持
     */

    class ListSupport {
        public <T> List<T> pop(String key) {
            return (List<T>) redisTemplate.opsForList().rightPop(key);
        }

        public boolean push(String key, Object value) {
            return redisTemplate.opsForList().leftPush(key, value) > 0;
        }
    }


    class HashSupport {

        public <T> List<T> values(String key) {
            return (List<T>) redisTemplate.opsForHash().values(key);
        }

        public <T> List<T> keys(String key) {
            return (List<T>) redisTemplate.opsForHash().keys(key);
        }

        public <K, V> Map<K, V> entries(String key) {
            return (Map<K, V>) redisTemplate.opsForHash().entries(key);
        }
    }

    /**
     * 公共操作
     */
    class CommonOperationSupport {

        /**
         * 判断是否存在指定key
         *
         * @param key
         * @return boolean
         * @author Ashe
         * @date 2019/12/26 0026 16:30
         * @since V1.0.0
         */
        public boolean hasKey(String key) {
            return redisTemplate.hasKey(key);
        }

        /**
         * 重命名key
         *
         * @param oldKey
         * @param newkey
         * @return boolean
         * @author Ashe
         * @date 2019/12/26 0026 16:43
         * @since V1.0.0
         */
        public boolean renameKey(String oldKey, String newkey) {
            return redisTemplate.renameIfAbsent(oldKey, newkey);
        }

        /**
         * 删除key
         *
         * @param key
         * @return boolean
         * @author Ashe
         * @date 2019/12/26 0026 16:31
         * @since V1.0.0
         */
        public boolean delKey(String key) {

            if (hasKey(key)) {
                return redisTemplate.delete(key);
            }
            return true;
        }

        /**
         * 从redis缓存中获取元素
         *
         * @param key
         * @param clazz
         * @return T
         * @author Ashe
         * @date 2019/12/27 0027 10:11
         * @since V1.0.0
         */
        public <T> T get(String key, Class<T> clazz) {
            if (List.class.isAssignableFrom(clazz)) {
                return (T) redisTemplate.opsForList().range(key, 0, redisTemplate.opsForList().size(key));
            }
            if (String.class.isAssignableFrom(clazz)) {
                return (T) redisTemplate.opsForValue().get(key);
            }
            return null;
        }

        /**
         * 设置缓存值
         * @param key
         * @param obj
         * @author Ashe
         * @date 2019/12/27 0027 10:23
         * @return void
         * @since V1.0.0
         */
        public void set(String key, Object obj) {

            if (List.class.isAssignableFrom(obj.getClass())) {
                redisTemplate.opsForList().leftPush(key, obj);
            }
            if (String.class.isAssignableFrom(obj.getClass())) {
                redisTemplate.opsForValue().set(key, obj);
            }
        }
    }


    /**
     * 有效时间管理
     */
    class ExpireSupport {
        /**
         * 指定key的过期时间
         *
         * @param key
         * @param timeUnit
         * @return boolean
         * @author Ashe
         * @date 2019/12/26 0026 16:04
         * @since V1.0.0
         */
        public boolean expire(String key, long time, TimeUnit timeUnit) {
            Boolean expire = redisTemplate.expire(key, time, timeUnit);
            return expire;
        }

        /**
         * 指定key的过期时间 默认秒为单位
         *
         * @param key
         * @param time
         * @return boolean
         * @author Ashe
         * @date 2019/12/26 0026 16:04
         * @since V1.0.0
         */
        public boolean expire(String key, long time) {
            Boolean expire = redisTemplate.expire(key, time, TimeUnit.SECONDS);
            return expire;
        }

        /**
         * 指定key的过期日期时间戳
         *
         * @param key
         * @return boolean
         * @author Ashe
         * @date 2019/12/26 0026 16:04
         * @since V1.0.0
         */
        public boolean expireAt(String key, Date date) {
            Boolean expire = redisTemplate.expireAt(key, date);
            return expire;
        }

        /**
         * 获取过期时间
         *
         * @param key
         * @return long
         * @author Ashe
         * @date 2019/12/26 0026 16:15
         * @since V1.0.0
         */
        public long getExpire(String key) {
            return redisTemplate.getExpire(key);
        }

        /**
         * 获取过期时间转换为固定时间单位
         *
         * @param key
         * @param timeUnit
         * @return java.lang.Long
         * @author Ashe
         * @date 2019/12/26 0026 16:15
         * @since V1.0.0
         */
        public Long getExpire(String key, TimeUnit timeUnit) {
            return redisTemplate.getExpire(key, timeUnit);
        }
    }


}

